package gov.pbc.nn.core.bdf.service;

import gov.pbc.nn.core.bdf.entity.User;
import gov.pbc.nn.core.dao.PbcnnCoreJdbcDao;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.lang.math.RandomUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import com.bstek.bdf2.core.business.IUser;
import com.bstek.bdf2.core.context.ContextHolder;
import com.bstek.bdf2.core.orm.ParseResult;
import com.bstek.bdf2.core.service.IUserService;
import com.bstek.dorado.core.resource.ResourceManager;
import com.bstek.dorado.core.resource.ResourceManagerUtils;
import com.bstek.dorado.data.entity.EntityUtils;
import com.bstek.dorado.data.provider.Criteria;
import com.bstek.dorado.data.provider.Page;

public class UserService implements IUserService {

	@Resource(name = PbcnnCoreJdbcDao.BEAN_ID)
	private PbcnnCoreJdbcDao jdbcDao;
	@Autowired
	@Qualifier("bdf2.passwordEncoder")
	private PasswordEncoder passwordEncoder;

	private static final ResourceManager resourceManager = ResourceManagerUtils.get(UserService.class);

	/**
	 * 根据用户帐号查找用户信息，返回User对象，找不到则抛出异常
	 */
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		String sql = "SELECT U.*,d.ID_,d.NAME_ FROM T_USER U LEFT JOIN bdf2_user_dept ud on u.USERNAME_=ud.USERNAME_ LEFT JOIN t_dept d on ud.DEPT_ID_=d.ID_ WHERE U.USERNAME_=?";
		List<IUser> users = jdbcDao.getJdbcTemplate().query(sql, new Object[] { username }, new DefaultUserRowMapper());
		if (users.size() == 0) {
			throw new UsernameNotFoundException("User " + username + " is not exist");
		} else {
			User user = (User) users.get(0);
			return user;
		}
	}

	/**
	 * 分页加载用户数据
	 * 
	 * @param page
	 *            Dorado7分页对象，其中包含pageNo,pageSize，分页后的数据也填充到这个page对象当中，该参数不可为空
	 * @param companyId
	 *            要加载哪个companyId下的用户信息，该参数不可为空
	 * @param criteria
	 *            Dorado7条件对象，可从中取到相应的条件值，该参数可为空。该条件可以包含用户和用户的属性信息。
	 */
	public void loadPageUsers(Page<IUser> page, String companyId, Criteria criteria) {
		String sql = "SELECT x.* FROM T_USER x WHERE ";
		sql = "SELECT\n" + " distinct T.*\n" + "FROM\n" + "	(\n" + "		SELECT\n"
				+ "			U.*, D.ID_ as DEPT_ID_,D.NAME_ AS DEPT_NAME_\n" + "		FROM\n" + "			t_user U\n"
				+ "		LEFT JOIN bdf2_user_dept UD ON U.USERNAME_ = UD.USERNAME_\n"
				+ "		LEFT JOIN t_dept D ON UD.DEPT_ID_ = D.ID_ order by D.ID_,U.USERNAME_\n" + "	) T where ";
		ParseResult result = jdbcDao.parseCriteria(criteria, false, "T");
		if (result != null) {
			StringBuffer sb = result.getAssemblySql();
			Map<String, Object> valueMap = result.getValueMap();
			valueMap.put("companyId", companyId);
			sql += sb.toString() + " and T.COMPANY_ID_=?";
			jdbcDao.pagingQuery(page, sql, valueMap.values().toArray(), new DefaultUserRowMapper());
		} else {
			jdbcDao.pagingQuery(page, sql + "T.COMPANY_ID_=?", new Object[] { companyId }, new DefaultUserRowMapper());
		}
	}

	/**
	 * 根据部门分页加载用户数据
	 * 
	 * @param page
	 *            Dorado7分页对象，其中包含pageNo,pageSize，分页后的数据也填充到这个page对象当中，该参数不可为空
	 * @param deptId
	 *            部门ID，不可为空
	 * @param criteria
	 *            Dorado7条件对象，可从中取到相应的条件值，该参数可为空。该条件可以包含用户和用户的属性信息。
	 */
	public void loadUsersByDeptIdForPage(Page<IUser> page, String deptId, Criteria criteria) {
		String sql = "SELECT\n" + "	DISTINCT *\n" + "FROM\n" + "	(\n" + "		SELECT\n"
				+ "			U.*, D.ID_ AS DEPT_ID_,\n" + "			D.NAME_ AS DEPT_NAME_\n" + "		FROM\n"
				+ "			t_user U\n" + "		INNER JOIN bdf2_user_dept UD ON U.USERNAME_ = UD.USERNAME_\n"
				+ "		INNER JOIN t_dept D ON UD.DEPT_ID_ = D.ID_  order by D.ID_,U.USERNAME_\n" + "	) T\n"
				+ "WHERE\n" + "	T.DEPT_ID_=:deptId";
		ParseResult result = jdbcDao.parseCriteria(criteria, true, "T");
		if (result != null) {
			StringBuffer sb = result.getAssemblySql();
			Map<String, Object> valueMap = result.getValueMap();
			sql += " AND " + sb.toString();
			valueMap.put("deptId", deptId);
			// this.pagingQuery(page, sql, valueMap.values().toArray(),
			// new DefaultUserRowMapper());
			jdbcDao.pagingQuery(page, sql, new DefaultUserRowMapper(), valueMap);
		} else {
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("deptId", deptId);
			jdbcDao.pagingQuery(page, sql, new DefaultUserRowMapper(), params);
			// this.pagingQuery(page, sql, new Object[] { deptId },
			// new DefaultUserRowMapper());
		}

		// this.pagingQuery(page, sql + "UD.DEPT_ID_=?", new Object[] { deptId
		// },
		// new DefaultUserRowMapper());
	}

	public Collection<IUser> loadUsersByDeptId(String deptId) {
		String sql = "SELECT x.* FROM BDF2_USER_DEPT UD INNER JOIN T_USER x ON UD.USERNAME_=x.USERNAME_ WHERE UD.DEPT_ID_=?";
		return jdbcDao.getJdbcTemplate().query(sql, new Object[] { deptId }, new DefaultUserRowMapper());
	}

	public void changePassword(String username, String newPassword) {
		String sql = "UPDATE T_USER SET PASSWORD_=? ,SALT_=?  WHERE USERNAME_=?";
		int salt = RandomUtils.nextInt(1000);
		jdbcDao.getJdbcTemplate().update(sql,
				new Object[] { passwordEncoder.encodePassword(newPassword, salt), String.valueOf(salt), username });
	}

	public String checkPassword(String username, String password) {
		User user = (User) ContextHolder.getLoginUser();
		String salt = user.getSalt();
		if (!passwordEncoder.isPasswordValid(user.getPassword(), password, salt)) {
			return resourceManager.getString("bdf2.core/passwordIncorrect");
		} else {
			return null;
		}
	}

	public IUser newUserInstance(String username) {
		return new User(username);
	}

	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
		this.passwordEncoder = passwordEncoder;
	}

	public void registerAdministrator(String username, String cname, String ename, String password, String email,
			String mobile, String companyId) {
		String sql = "INSERT INTO T_USER(USERNAME_,CNAME_,ENAME_,PASSWORD_,SALT_,ENABLED_,ADMINISTRATOR_,EMAIL_,MOBILE_,COMPANY_ID_,MALE_) VALUES(?,?,?,?,?,?,?,?,?,?,?)";
		int salt = RandomUtils.nextInt(1000);
		password = passwordEncoder.encodePassword(password, salt);
		jdbcDao.getJdbcTemplate().update(sql, new Object[] { username, cname, ename, password, String.valueOf(salt),
				true, true, email, mobile, companyId, true });
	}

	public static class DefaultUserRowMapper implements RowMapper<IUser> {
		public User mapRow(ResultSet rs, int rowNum) throws SQLException {
			User user = new User();
			user.setUsername(rs.getString("USERNAME_"));
			user.setCname(rs.getString("CNAME_"));
			user.setEname(rs.getString("ENAME_"));
			user.setAdministrator(rs.getBoolean("ADMINISTRATOR_"));
			user.setBirthday(rs.getDate("BIRTHDAY_"));
			user.setCompanyId(rs.getString("COMPANY_ID_"));
			user.setEmail(rs.getString("EMAIL_"));
			user.setEnabled(rs.getBoolean("ENABLED_"));
			user.setMale(rs.getBoolean("MALE_"));
			user.setMobile(rs.getString("MOBILE_"));
			user.setPassword(rs.getString("PASSWORD_"));
			user.setSalt(rs.getString("SALT_"));
			user.setAddress(rs.getString("ADDRESS_"));
			user.setIdentity(rs.getString("IDENTITY_"));
			user.setDuty(rs.getString("DUTY_"));

			try {
				user = EntityUtils.toEntity(user);
			} catch (Exception e) {
			}
			try {
				EntityUtils.setValue(user, "deptId", rs.getString("DEPT_ID_"));// 部门ID
			} catch (Exception e) {

			}
			try {
				EntityUtils.setValue(user, "deptName", rs.getString("DEPT_NAME_"));// 部门名称
			} catch (Exception e) {

			}
			return user;
		}

	}
}
